<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Service与Mapper的艺术 - Java分层架构指南</title>
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            line-height: 1.8;
            color: #333;
            background-color: #f9f9f9;
        }
        h1, h2, h3, h4, h5, h6 {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
        }
        .drop-cap::first-letter {
            font-size: 3.5em;
            float: left;
            line-height: 0.8;
            margin-right: 0.1em;
            color: #4a5568;
        }
        .code-block {
            position: relative;
            border-radius: 8px;
            overflow: hidden;
        }
        .code-header {
            background: #2d3748;
            color: #e2e8f0;
            padding: 0.5rem 1rem;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            display: flex;
            justify-content: space-between;
        }
        .code-body {
            background: #1a202c;
            color: #cbd5e0;
            padding: 1rem;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.5;
            tab-size: 4;
        }
        .card-hover {
            transition: all 0.3s ease;
        }
        .card-hover:hover {
            transform: translateY(-5px);
            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .table-container {
            overflow-x: auto;
        }
        .table-custom {
            min-width: 100%;
            border-collapse: separate;
            border-spacing: 0;
        }
        .table-custom th {
            background: #4a5568;
            color: white;
            font-weight: 500;
            padding: 0.75rem 1rem;
            text-align: left;
        }
        .table-custom td {
            padding: 0.75rem 1rem;
            border-bottom: 1px solid #e2e8f0;
            vertical-align: top;
        }
        .table-custom tr:nth-child(even) {
            background: #f7fafc;
        }
        .table-custom tr:hover {
            background: #ebf8ff;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <div class="relative bg-gradient-to-r from-blue-900 to-indigo-800 text-white py-24 px-4 sm:px-6 lg:px-8">
        <div class="max-w-5xl mx-auto text-center">
            <div class="flex justify-center mb-6">
                <span class="px-4 py-2 bg-blue-700 rounded-full text-sm font-medium">Java架构</span>
            </div>
            <h1 class="text-4xl md:text-5xl font-bold leading-tight mb-6">Service与Mapper的艺术</h1>
            <p class="text-xl md:text-2xl text-blue-100 max-w-3xl mx-auto">Java分层架构中的职责边界与最佳实践</p>
            <div class="mt-10">
                <img src="https://cdn.nlark.com/yuque/0/2025/png/21449790/1740380826954-6ab9bb38-4122-48de-91bc-9e87fbdfe523.png" alt="餐厅三层架构比喻" class="mx-auto rounded-lg shadow-xl w-full max-w-2xl">
            </div>
        </div>
    </div>

    <!-- Main Content -->
    <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
        <!-- Intro Section -->
        <section class="mb-20">
            <div class="drop-cap text-gray-700 text-lg leading-relaxed mb-8">
                想象你走进一家餐厅，整个用餐过程涉及三个角色：服务员负责接待顾客、记录需求、协调后厨；厨师专注烹饪、处理食材、制作菜品；传菜员负责传递菜品、响应顾客需求。这正好对应Java项目中的三层架构！通过这个比喻，我们能轻松理解Service与Mapper的关系。
            </div>
            <div class="bg-white rounded-xl shadow-md overflow-hidden p-6 mb-8">
                <div class="flex flex-col md:flex-row items-center">
                    <div class="md:w-1/2 mb-6 md:mb-0 md:pr-6">
                        <h3 class="text-xl font-semibold text-gray-800 mb-4">餐厅角色与Java架构对应关系</h3>
                        <ul class="space-y-3">
                            <li class="flex items-start">
                                <div class="flex-shrink-0 h-6 w-6 text-blue-600">
                                    <i class="fas fa-user-tie"></i>
                                </div>
                                <p class="ml-3 text-gray-700"><span class="font-medium">服务员 (Service)</span> - 接待顾客、记录需求、协调后厨</p>
                            </li>
                            <li class="flex items-start">
                                <div class="flex-shrink-0 h-6 w-6 text-green-600">
                                    <i class="fas fa-utensils"></i>
                                </div>
                                <p class="ml-3 text-gray-700"><span class="font-medium">厨师 (Mapper)</span> - 专注烹饪、处理食材、制作菜品</p>
                            </li>
                            <li class="flex items-start">
                                <div class="flex-shrink-0 h-6 w-6 text-purple-600">
                                    <i class="fas fa-people-carry"></i>
                                </div>
                                <p class="ml-3 text-gray-700"><span class="font-medium">传菜员 (Controller)</span> - 传递菜品、响应顾客需求</p>
                            </li>
                        </ul>
                    </div>
                    <div class="md:w-1/2">
                        <div class="bg-gray-100 p-4 rounded-lg">
                            <div class="mermaid">
                                graph TD
                                    A[顾客] -->|下单| B[Controller]
                                    B -->|传递需求| C[Service]
                                    C -->|准备食材| D[Mapper]
                                    D -->|返回数据| C
                                    C -->|上菜| B
                                    B -->|服务完成| A
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- 分层架构 Section -->
        <section class="mb-20">
            <h2 class="text-3xl font-bold text-gray-800 mb-8 border-b pb-4">分层架构：代码世界的"社会分工"</h2>
            
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">2.1 传统三层架构</h3>
                <div class="flex flex-col md:flex-row gap-8 mb-8">
                    <div class="md:w-1/2">
                        <img src="https://cdn.nlark.com/yuque/0/2025/png/21449790/1740380860063-b7243eb8-82c0-4c9e-b664-2d3784c0bc78.png" alt="三层架构图示" class="w-full rounded-lg shadow-md">
                    </div>
                    <div class="md:w-1/2">
                        <div class="bg-white rounded-lg shadow-md overflow-hidden">
                            <div class="table-container">
                                <table class="table-custom w-full">
                                    <thead>
                                        <tr>
                                            <th>层级</th>
                                            <th>类比角色</th>
                                            <th>职责描述</th>
                                            <th>代码示例</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <tr>
                                            <td>Controller层</td>
                                            <td>传菜员</td>
                                            <td>接收请求，返回响应</td>
                                            <td>@RestController</td>
                                        </tr>
                                        <tr>
                                            <td>Service层</td>
                                            <td>服务员</td>
                                            <td>处理业务逻辑，协调数据操作</td>
                                            <td>@Service</td>
                                        </tr>
                                        <tr>
                                            <td>Mapper层</td>
                                            <td>厨师</td>
                                            <td>专注数据库操作</td>
                                            <td>@Mapper</td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">2.2 为什么需要分层？</h3>
                <div class="grid md:grid-cols-3 gap-6">
                    <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
                        <div class="p-6">
                            <div class="flex items-center mb-4">
                                <div class="flex-shrink-0 h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600">
                                    <i class="fas fa-unlink"></i>
                                </div>
                                <h4 class="ml-3 text-lg font-medium text-gray-900">解耦合</h4>
                            </div>
                            <p class="text-gray-600">修改数据库不影响业务逻辑，各层职责明确，变更影响范围可控</p>
                        </div>
                    </div>
                    <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
                        <div class="p-6">
                            <div class="flex items-center mb-4">
                                <div class="flex-shrink-0 h-10 w-10 rounded-full bg-green-100 flex items-center justify-center text-green-600">
                                    <i class="fas fa-tools"></i>
                                </div>
                                <h4 class="ml-3 text-lg font-medium text-gray-900">可维护性</h4>
                            </div>
                            <p class="text-gray-600">各司其职，代码结构清晰，问题定位快速准确</p>
                        </div>
                    </div>
                    <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
                        <div class="p-6">
                            <div class="flex items-center mb-4">
                                <div class="flex-shrink-0 h-10 w-10 rounded-full bg-purple-100 flex items-center justify-center text-purple-600">
                                    <i class="fas fa-redo"></i>
                                </div>
                                <h4 class="ml-3 text-lg font-medium text-gray-900">复用性</h4>
                            </div>
                            <p class="text-gray-600">同一Service可调用多个Mapper，业务组件可重复使用</p>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Service vs Mapper Section -->
        <section class="mb-20">
            <h2 class="text-3xl font-bold text-gray-800 mb-8 border-b pb-4">Service vs Mapper：职责边界详解</h2>
            
            <div class="mb-12">
                <div class="flex justify-center mb-8">
                    <img src="https://cdn.nlark.com/yuque/0/2025/png/21449790/1740380901788-9c6fdcf0-8001-4859-88c6-cacbf7c87d5e.png" alt="Service与Mapper职责边界" class="rounded-lg shadow-md max-w-3xl">
                </div>

                <div class="grid md:grid-cols-2 gap-8">
                    <div class="bg-white rounded-xl shadow-md overflow-hidden">
                        <div class="p-6">
                            <h3 class="text-2xl font-semibold text-gray-800 mb-6 flex items-center">
                                <div class="flex-shrink-0 h-10 w-10 rounded-full bg-green-100 flex items-center justify-center text-green-600 mr-4">
                                    <i class="fas fa-utensils"></i>
                                </div>
                                Mapper层：专注数据的"手艺人"
                            </h3>
                            
                            <div class="mb-6">
                                <h4 class="text-lg font-medium text-gray-900 mb-3">核心职责</h4>
                                <ul class="space-y-2">
                                    <li class="flex items-start">
                                        <div class="flex-shrink-0 h-5 w-5 text-green-500 mt-0.5">
                                            <i class="fas fa-check-circle"></i>
                                        </div>
                                        <p class="ml-2 text-gray-700">执行SQL操作（增删改查）</p>
                                    </li>
                                    <li class="flex items-start">
                                        <div class="flex-shrink-0 h-5 w-5 text-green-500 mt-0.5">
                                            <i class="fas fa-check-circle"></i>
                                        </div>
                                        <p class="ml-2 text-gray-700">处理基础数据转换</p>
                                    </li>
                                </ul>
                            </div>
                            
                            <div>
                                <h4 class="text-lg font-medium text-gray-900 mb-3">不该做的事</h4>
                                <ul class="space-y-2">
                                    <li class="flex items-start">
                                        <div class="flex-shrink-0 h-5 w-5 text-red-500 mt-0.5">
                                            <i class="fas fa-times-circle"></i>
                                        </div>
                                        <p class="ml-2 text-gray-700">处理业务逻辑</p>
                                    </li>
                                    <li class="flex items-start">
                                        <div class="flex-shrink-0 h-5 w-5 text-red-500 mt-0.5">
                                            <i class="fas fa-times-circle"></i>
                                        </div>
                                        <p class="ml-2 text-gray-700">进行数据校验</p>
                                    </li>
                                    <li class="flex items-start">
                                        <div class="flex-shrink-0 h-5 w-5 text-red-500 mt-0.5">
                                            <i class="fas fa-times-circle"></i>
                                        </div>
                                        <p class="ml-2 text-gray-700">处理事务</p>
                                    </li>
                                </ul>
                            </div>
                            
                            <div class="mt-8">
                                <h4 class="text-lg font-medium text-gray-900 mb-3">典型Mapper接口</h4>
                                <div class="code-block">
                                    <div class="code-header">
                                        <span>UserMapper.java</span>
                                        <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                                    </div>
                                    <div class="code-body">
                                        <pre><code>@Mapper
public interface UserMapper {
    // 简单查询
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(Long id);

    // 插入数据
    @Insert("INSERT INTO users(name,age) VALUES(#{name},#{age})")
    int insert(User user);
}</code></pre>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <div class="bg-white rounded-xl shadow-md overflow-hidden">
                        <div class="p-6">
                            <h3 class="text-2xl font-semibold text-gray-800 mb-6 flex items-center">
                                <div class="flex-shrink-0 h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 mr-4">
                                    <i class="fas fa-user-tie"></i>
                                </div>
                                Service层：业务逻辑的"指挥官"
                            </h3>
                            
                            <div class="mb-6">
                                <h4 class="text-lg font-medium text-gray-900 mb-3">核心职责</h4>
                                <ul class="space-y-2">
                                    <li class="flex items-start">
                                        <div class="flex-shrink-0 h-5 w-5 text-blue-500 mt-0.5">
                                            <i class="fas fa-check-circle"></i>
                                        </div>
                                        <p class="ml-2 text-gray-700">组合多个Mapper操作</p>
                                    </li>
                                    <li class="flex items-start">
                                        <div class="flex-shrink-0 h-5 w-5 text-blue-500 mt-0.5">
                                            <i class="fas fa-check-circle"></i>
                                        </div>
                                        <p class="ml-2 text-gray-700">实现业务规则</p>
                                    </li>
                                    <li class="flex items-start">
                                        <div class="flex-shrink-0 h-5 w-5 text-blue-500 mt-0.5">
                                            <i class="fas fa-check-circle"></i>
                                        </div>
                                        <p class="ml-2 text-gray-700">处理事务</p>
                                    </li>
                                    <li class="flex items-start">
                                        <div class="flex-shrink-0 h-5 w-5 text-blue-500 mt-0.5">
                                            <i class="fas fa-check-circle"></i>
                                        </div>
                                        <p class="ml-2 text-gray-700">异常处理</p>
                                    </li>
                                </ul>
                            </div>
                            
                            <div class="mt-8">
                                <h4 class="text-lg font-medium text-gray-900 mb-3">典型Service类</h4>
                                <div class="code-block">
                                    <div class="code-header">
                                        <span>UserService.java</span>
                                        <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                                    </div>
                                    <div class="code-body">
                                        <pre><code>@Service
public class UserService {
    private final UserMapper userMapper;
    private final OrderMapper orderMapper;

    // 事务管理
    @Transactional
    public void createUserWithOrder(User user, Order order) {
        // 业务校验
        if (user.getAge() < 18) {
            throw new IllegalArgumentException("未成年人禁止注册");
        }
        
        // 组合Mapper操作
        userMapper.insert(user);
        order.setUserId(user.getId());
        orderMapper.insert(order);
        
        // 发送通知
        sendWelcomeEmail(user);
    }
}</code></pre>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- 实战案例 Section -->
        <section class="mb-20">
            <h2 class="text-3xl font-bold text-gray-800 mb-8 border-b pb-4">实战案例：用户积分管理系统</h2>
            
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">4.1 需求场景</h3>
                <div class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-8">
                    <div class="flex">
                        <div class="flex-shrink-0">
                            <i class="fas fa-info-circle text-blue-500"></i>
                        </div>
                        <div class="ml-3">
                            <p class="text-blue-700">
                                + 用户完成订单获得积分<br>
                                + 积分可用于兑换优惠券<br>
                                + 积分变动需要记录日志
                            </p>
                        </div>
                    </div>
                </div>
                
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">4.2 代码实现</h3>
                <div class="grid md:grid-cols-2 gap-8 mb-8">
                    <div>
                        <h4 class="text-xl font-medium text-gray-800 mb-4">Mapper层</h4>
                        <div class="code-block mb-6">
                            <div class="code-header">
                                <span>UserMapper.java</span>
                                <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <div class="code-body">
                                <pre><code>@Mapper
public interface UserMapper {
    @Update("UPDATE users SET points = points + #{points} WHERE id = #{userId}")
    int updatePoints(@Param("userId") Long userId, @Param("points") int points);
}</code></pre>
                            </div>
                        </div>
                        <div class="code-block">
                            <div class="code-header">
                                <span>PointsLogMapper.java</span>
                                <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <div class="code-body">
                                <pre><code>@Mapper
public interface PointsLogMapper {
    @Insert("INSERT INTO points_log(user_id, points, type) VALUES(#{userId}, #{points}, #{type})")
    int insertLog(PointsLog log);
}</code></pre>
                            </div>
                        </div>
                    </div>
                    
                    <div>
                        <h4 class="text-xl font-medium text-gray-800 mb-4">Service层</h4>
                        <div class="code-block">
                            <div class="code-header">
                                <span>PointsService.java</span>
                                <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <div class="code-body">
                                <pre><code>@Service
public class PointsService {
    private final UserMapper userMapper;
    private final PointsLogMapper logMapper;

    @Transactional
    public void addPoints(Long userId, int points, String type) {
        // 检查积分合法性
        if (points <= 0) {
            throw new IllegalArgumentException("积分必须为正数");
        }
        
        // 更新用户积分
        int rows = userMapper.updatePoints(userId, points);
        if (rows == 0) {
            throw new RuntimeException("用户不存在");
        }
        
        // 记录日志
        PointsLog log = new PointsLog(userId, points, type);
        logMapper.insertLog(log);
        
        // 检查积分等级
        checkLevelUp(userId);
    }
    
    private void checkLevelUp(Long userId) {
        // 复杂的等级计算逻辑
    }
}</code></pre>
                            </div>
                        </div>
                    </div>
                </div>
                
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">4.3 流程解析</h3>
                <div class="bg-white rounded-lg shadow-md p-6">
                    <div class="mermaid">
                        sequenceDiagram
                            participant C as Controller
                            participant S as Service
                            participant M1 as UserMapper
                            participant M2 as PointsLogMapper
                            
                            C->>S: 添加积分请求(userId, points, type)
                            S->>S: 校验参数合法性
                            S->>M1: 更新用户积分
                            M1-->>S: 返回影响行数
                            S->>M2: 记录积分日志
                            M2-->>S: 返回结果
                            S->>S: 检查积分等级
                            S-->>C: 返回操作结果
                    </div>
                </div>
            </div>
        </section>

        <!-- 常见问题 Section -->
        <section class="mb-20">
            <h2 class="text-3xl font-bold text-gray-800 mb-8 border-b pb-4">常见问题剖析</h2>
            
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">5.1 把业务逻辑写在Mapper层？</h3>
                
                <div class="grid md:grid-cols-2 gap-8 mb-8">
                    <div>
                        <h4 class="text-lg font-medium text-red-700 mb-4">错误示范</h4>
                        <div class="code-block">
                            <div class="code-header">
                                <span>OrderMapper.java</span>
                                <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <div class="code-body">
                                <pre><code>@Mapper
public interface OrderMapper {
    @Select("SELECT * FROM orders WHERE user_id = #{userId}")
    List&lt;Order&gt; findByUserId(Long userId);
    
    // 错误！业务逻辑不应出现在Mapper
    default List&lt;Order&gt; findValidOrders(Long userId) {
        return findByUserId(userId).stream()
                                  .filter(o -> o.getStatus() == 1)
                                  .collect(Collectors.toList());
    }
}</code></pre>
                            </div>
                        </div>
                    </div>
                    
                    <div>
                        <h4 class="text-lg font-medium text-green-700 mb-4">正确做法</h4>
                        <div class="code-block">
                            <div class="code-header">
                                <span>OrderService.java</span>
                                <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <div class="code-body">
                                <pre><code>// Service层处理业务过滤
public List&lt;Order&gt; getValidOrders(Long userId) {
    return orderMapper.findByUserId(userId).stream()
                      .filter(o -> o.isValid())
                      .collect(Collectors.toList());
}</code></pre>
                            </div>
                        </div>
                    </div>
                </div>
                
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">5.2 Service变成"Mapper大杂烩"？</h3>
                
                <div class="grid md:grid-cols-2 gap-8">
                    <div>
                        <h4 class="text-lg font-medium text-red-700 mb-4">错误示范</h4>
                        <div class="code-block">
                            <div class="code-header">
                                <span>BadService.java</span>
                                <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <div class="code-body">
                                <pre><code>@Service
public class BadService {
    public void badMethod() {
        // 直接暴露数据库操作细节
        userMapper.updateName(id, name);
        orderMapper.updateStatus(orderId, 2);
        logMapper.insert(log);
    }
}</code></pre>
                            </div>
                        </div>
                    </div>
                    
                    <div>
                        <h4 class="text-lg font-medium text-green-700 mb-4">正确做法</h4>
                        <div class="code-block">
                            <div class="code-header">
                                <span>GoodService.java</span>
                                <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <div class="code-body">
                                <pre><code>@Service
public class GoodService {
    public void goodMethod(User user, Order order) {
        updateUserInfo(user);
        processOrder(order);
        recordOperationLog(user, order);
    }
    
    // 封装具体操作
    private void updateUserInfo(User user) { /*...*/ }
    private void processOrder(Order order) { /*...*/ }
}</code></pre>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- 最佳实践指南 Section -->
        <section class="mb-20">
            <h2 class="text-3xl font-bold text-gray-800 mb-8 border-b pb-4">最佳实践指南</h2>
            
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">6.1 接口设计原则</h3>
                
                <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8">
                    <div class="table-container">
                        <table class="table-custom w-full">
                            <thead>
                                <tr>
                                    <th>原则</th>
                                    <th>Mapper层</th>
                                    <th>Service层</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr>
                                    <td>单一职责</td>
                                    <td>每个方法对应一个SQL操作</td>
                                    <td>每个方法对应一个业务用例</td>
                                </tr>
                                <tr>
                                    <td>抽象层级</td>
                                    <td>原子操作</td>
                                    <td>组合操作</td>
                                </tr>
                                <tr>
                                    <td>方法命名</td>
                                    <td>insertXxx/updateXxx</td>
                                    <td>processXxx/handleXxx</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
                
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">6.2 事务管理</h3>
                
                <div class="grid md:grid-cols-2 gap-8 mb-8">
                    <div>
                        <h4 class="text-lg font-medium text-green-700 mb-4">正确姿势</h4>
                        <div class="code-block">
                            <div class="code-header">
                                <span>OrderService.java</span>
                                <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <div class="code-body">
                                <pre><code>@Service
public class OrderService {
    @Transactional
    public void placeOrder(Order order) {
        // 扣库存
        productMapper.reduceStock(order.getProductId(), order.getQuantity());
        
        // 创建订单
        orderMapper.insert(order);
        
        // 扣余额
        userMapper.deductBalance(order.getUserId(), order.getTotalAmount());
    }
}</code></pre>
                            </div>
                        </div>
                    </div>
                    
                    <div>
                        <h4 class="text-lg font-medium text-red-700 mb-4">常见错误</h4>
                        <div class="code-block">
                            <div class="code-header">
                                <span>UserMapper.java</span>
                                <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <div class="code-body">
                                <pre><code>// 错误！事务注解应加在Service
@Mapper
public interface UserMapper {
    @Transactional // 错误位置！
    @Update("...")
    void deductBalance(...);
}</code></pre>
                            </div>
                        </div>
                    </div>
                </div>
                
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">6.3 异常处理</h3>
                
                <div class="code-block mb-8">
                    <div class="code-header">
                        <span>UserService.java</span>
                        <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                    </div>
                    <div class="code-body">
                        <pre><code>@Service
public class UserService {
    public User getUserById(Long id) {
        return userMapper.findById(id)
                        .orElseThrow(() -> new UserNotFoundException(id));
    }
    
    public void updateEmail(Long userId, String email) {
        if (!isValidEmail(email)) {
            throw new InvalidEmailFormatException(email);
        }
        userMapper.updateEmail(userId, email);
    }
}</code></pre>
                    </div>
                </div>
            </div>
        </section>

        <!-- 高级技巧 Section -->
        <section class="mb-20">
            <h2 class="text-3xl font-bold text-gray-800 mb-8 border-b pb-4">高级技巧：让分层更清晰</h2>
            
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">7.1 DTO（Data Transfer Object）模式</h3>
                
                <div class="bg-white rounded-lg shadow-md p-6 mb-8">
                    <div class="mermaid">
                        graph LR
                            A[前端] -->|UserCreateRequest| B[Controller]
                            B -->|User| C[Service]
                            C -->|User| D[Mapper]
                            D -->|User| C
                            C -->|User| B
                            B -->|UserDTO| A
                    </div>
                </div>
                
                <div class="code-block">
                    <div class="code-header">
                        <span>代码示例</span>
                        <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                    </div>
                    <div class="code-body">
                        <pre><code>// Controller层
@PostMapping("/users")
public UserDTO createUser(@RequestBody UserCreateRequest request) {
    User user = userService.createUser(request);
    return UserConverter.toDTO(user);
}

// Service层
@Service
public class UserService {
    public User createUser(UserCreateRequest request) {
        User user = new User();
        user.setName(request.getName());
        user.setAge(request.getAge());
        userMapper.insert(user);
        return user;
    }
}

// Mapper层保持纯POJO操作</code></pre>
                    </div>
                </div>
            </div>
            
            <div>
                <h3 class="text-2xl font-semibold text-gray-800 mb-6">7.2 单元测试策略</h3>
                
                <div class="grid md:grid-cols-2 gap-8">
                    <div>
                        <h4 class="text-xl font-medium text-gray-800 mb-4">Mapper测试</h4>
                        <div class="bg-yellow-50 border-l-4 border-yellow-500 p-4 mb-4">
                            <div class="flex">
                                <div class="flex-shrink-0">
                                    <i class="fas fa-lightbulb text-yellow-500"></i>
                                </div>
                                <div class="ml-3">
                                    <p class="text-yellow-700">
                                        + 专注数据库操作的正确性<br>
                                        + 使用内存数据库（如H2）
                                    </p>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <div>
                        <h4 class="text-xl font-medium text-gray-800 mb-4">Service测试</h4>
                        <div class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-4">
                            <div class="flex">
                                <div class="flex-shrink-0">
                                    <i class="fas fa-lightbulb text-blue-500"></i>
                                </div>
                                <div class="ml-3">
                                    <p class="text-blue-700">
                                        + Mock Mapper层<br>
                                        + 验证业务逻辑
                                    </p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                
                <div class="code-block mt-6">
                    <div class="code-header">
                        <span>UserServiceTest.java</span>
                        <button class="text-blue-300 hover:text-white" onclick="copyCode(this)">复制代码</button>
                    </div>
                    <div class="code-body">
                        <pre><code>class UserServiceTest {
    @Mock
    private UserMapper userMapper;
    
    @InjectMocks
    private UserService userService;

    @Test
    void createUser_ValidAge_Success() {
        UserCreateRequest request = new UserCreateRequest("Alice", 20);
        when(userMapper.insert(any())).thenReturn(1);
        
        User user = userService.createUser(request);
        
        assertNotNull(user.getId());
        verify(userMapper).insert(any());
    }
}</code></pre>
                    </div>
                </div>
            </div>
        </section>

        <!-- Conclusion Section -->
        <section class="mb-20 bg-white rounded-xl shadow-md overflow-hidden p-8">
            <div class="text-center">
                <h2 class="text-3xl font-bold text-gray-800 mb-6">掌握分层架构的艺术</h2>
                <p class="text-xl text-gray-600 mb-8 max-w-3xl mx-auto">
                    Service与Mapper的分工协作是Java企业级应用的基础，理解它们的职责边界能够让你写出更优雅、更易维护的代码。记住餐厅的比喻：服务员(Service)协调全局，厨师(Mapper)专注细节，传菜员(Controller)连接前后端。
                </p>
                <div class="flex justify-center">
                    <div class="inline-flex rounded-md shadow">
                        <a href="http://www.yuque.com/jtostring" class="inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700">
                            访问技术小馆获取更多资源
                            <i class="fas fa-external-link-alt ml-2"></i>
                        </a>
                    </div>
                </div>
            </div>
        </section>
    </div>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-8">
        <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
            <div class="md:flex md:items-center md:justify-between">
                <div class="flex justify-center md:order-2 space-x-6">
                    <a href="http://www.yuque.com/jtostring" class="text-gray-400 hover:text-white">
                        <i class="fas fa-external-link-alt"></i>
                    </a>
                </div>
                <div class="mt-8 md:mt-0 md:order-1 text-center md:text-left">
                    <p class="text-base">
                        &copy; <span class="font-medium">技术小馆</span>. 保留所有权利.
                    </p>
                    <p class="text-sm mt-1">
                        地址: <a href="http://www.yuque.com/jtostring" class="text-blue-400 hover:text-blue-300">http://www.yuque.com/jtostring</a>
                    </p>
                </div>
            </div>
        </div>
    </footer>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            },
            sequence: {
                useMaxWidth: true,
                height: 40,
                actorMargin: 60
            }
        });
        
        function copyCode(button) {
            const codeBlock = button.closest('.code-block').querySelector('.code-body pre code');
            const range = document.createRange();
            range.selectNode(codeBlock);
            window.getSelection().removeAllRanges();
            window.getSelection().addRange(range);
            document.execCommand('copy');
            window.getSelection().removeAllRanges();
            
            const originalText = button.textContent;
            button.textContent = '已复制!';
            setTimeout(() => {
                button.textContent = originalText;
            }, 2000);
        }
    </script>
</body>
</html>